/*
 * Copyright (c) 2010-2013 Ruben Chakhmakhchyan. All rights reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Eclipse Public License
 * Version 1.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://opensource.org/licenses/EPL-1.0 and read it before using this file.
 */

#pragma once


#include "commontypes.h"

#include "list.h"
#include <string.h>
#include "strings.h"


class PdfObject abstract
{
public:

    enum class Type { Catalog = 1, Pages = 2, Page = 3, PageContent = 4, Image = 5 };

public:

    PdfObject() : m_id( 0 ) { }

    virtual ~PdfObject()
    {
        int i = 0;
    }

    inline uint_t getId() const { return m_id; }
    inline void setId( uint_t value ) { m_id = value; }

    virtual Type getType() const = 0;

private:

    uint_t m_id;
};


class PdfNamedObject : public PdfObject
{
public:

    PdfNamedObject() : m_name( 0 ) { }

    virtual ~PdfNamedObject()
    {
        delete m_name;
    }

    const char* getName() const { return m_name; }
    void setName( char* value )
    {
        size_t length = String::GetLength( value );
        m_name = new char[ length + 1 ];
        ::memset( m_name, 0, length + 1 );
        ::memcpy( m_name, value, length );
    }

private:

    char* m_name;
};


class PdfCatalog : public PdfObject
{
public:

    PdfCatalog() { setId( 1 ); }

    virtual Type getType() const { return Type::Catalog; }
};

enum class PdfEncoding : byte_t
{
    None = 0,
    CCITTG4 = 1,
    DCT = 2,
    Flate = 3,

};

class PdfImage : public PdfNamedObject
{
public:

    PdfImage() : m_size( 0 ), m_data( 0 ), m_width( 0 ), m_height( 0 ), m_resolution( 0 ), m_bitsPerComponent( 0 ), m_bitCount( 0 ) { }

    PdfImage( byte_t* data, PdfEncoding encoding, uint_t size, uint_t width, uint_t height, uint_t resolution, byte_t bitsPerComponent, byte_t bitCount, bool blackIs1 )
        : m_data( data ), m_size( size ), m_width( width ), m_height( height ), m_resolution( resolution ), m_encoding( ( byte_t ) encoding ), m_bitsPerComponent( bitsPerComponent ), m_bitCount( bitCount ), m_blackIs1( blackIs1 ) { }

    virtual ~PdfImage() { }

    void load( char* filename );

    inline uint_t getSize() const { return m_size; }

    byte_t* getData() const { return m_data; }

    void clear()
    {
        delete m_data;
        m_data = NULL;
    }

    virtual Type getType() const { return Type::Image; }

    inline byte_t getEncoding() const { return m_encoding; }
    inline uint_t getHeight() const { return m_height; }
    inline uint_t getWidth() const { return m_width; }
    inline uint_t getResolution() const { return m_resolution; }
    inline uint_t getBitsPerComponent() const { return m_bitsPerComponent; }\
        inline uint_t getBitCount() const { return m_bitCount; }
    inline uint_t getBlackIs1() const { return m_blackIs1; }

private:

    byte_t m_encoding;

    byte_t m_bitCount;
    byte_t m_bitsPerComponent;

    uint_t m_height;
    uint_t m_width;
    uint_t m_resolution;
    bool m_blackIs1;

    uint_t m_size; // image file size
    byte_t* m_data;
};


class PdfPage : public PdfObject
{
public:

    PdfPage() { }

    virtual Type getType() const { return Type::Page; }

    void drawImage( PdfImage* image );

    PdfImage& getImage() const { return *m_image; }

private:

    uint_t m_count;

    PdfImage* m_image;
};

class PdfPageContent : public PdfObject
{
public:

    PdfPageContent( PdfPage* page ) : m_page( page ) { }

    virtual Type getType() const { return Type::PageContent; }

    PdfPage& getPage() const { return *m_page; }

private:

    PdfPage* m_page;
};


class PdfPages : public PdfObject
{
public:

    PdfPages() : m_count( 0 ) { setId( 2 ); }

    virtual Type getType() const { return Type::Pages; }

    inline uint_t getCount() const { return m_count; }
    inline void setCount( uint_t value ) { m_count = value; }

    void addPages( uint_t count );

    PdfPage& getPage( uint_t index ) const { return *m_pages[ index ]; }

    const List<PdfPage*>& getPages() const { return m_pages; }

private:

    List<PdfPage*> m_pages;

    uint_t m_count;
};
